Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
Document
#root
@charset "UTF-8"; @import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800); *, :after, :before { box-sizing: border-box; padding: 0; margin: 0; } @import url('https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900&display=swap'); @mixin flexCenter { display: flex; justify-content: center; align-items: center; } * { box-sizing: border-box; } html { font-size: 100vmax / 1600 * 100; @media (max-width: 992px) { font-size: 60px; } } body { min-height: 100vh; @include flexCenter; color: #222; background-color: #ececec; font-size: 0.2rem; font-family: "Raleway", sans-serif; --card-width: clamp(6rem, 50dvw, 10rem); --card-height: clamp(4rem, 75dvh, 5rem); } input { display: none; } label { display: block; width: var(--card-width); height: var(--card-height); background-color: #fff; border-radius: 0.3rem; border: 2px dashed transparent; overflow: hidden; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 0.3rem; transition: all 0.3s; cursor: pointer; &.dragging { border-color: var(--dark-color); } &:active { .face .eye { // close eyes animation: none; transform: scaleY(0.2); } } .desc { font-size: 0.28rem; font-weight: bold; } } .face { position: relative; width: 2.5rem; height: 2.5rem; border-radius: 50%; background-color: var(--light-color); .eyes { position: absolute; top: 10%; left: 0; right: 0; margin: auto; width: 100%; height: 20%; display: flex; justify-content: center; align-items: center; gap: 20%; transition: all 0.2s; } .eye { width: 0.1rem; height: 0.1rem; border-radius: 50%; background-color: var(--dark-color); // close eyes transform-origin: bottom center; transition: all 0.3s; animation: blink 2s linear both infinite; } .mouth { position: absolute; bottom: 50%; left: 0; right: 0; margin: auto; width: 80%; height: 65%; border-radius: 50%; border: 3px solid transparent; border-bottom-color: var(--dark-color); transition: all 0.2s; } } img { max-width: var(--card-width); max-height: var(--card-height); object-fit: contain; border-radius: 0.3rem; box-shadow: 0 0 15px rgba(#000, 0.2); } .message-box { position: fixed; top: 0.2rem; left: 0; right: 0; width: fit-content; margin: auto; padding: 0.15rem 0.3rem; border-radius: 0.1rem; box-shadow: 2px 2px 10px rgba(#000, 0.2); backdrop-filter: blur(10px); animation: fadeIn 0.3s; } .reset-btn { position: absolute; bottom: 0.5rem; right: 0.5rem; padding: 0.12rem 0.4rem; border-radius: 0.1rem; background-color: indianred; color: white; box-shadow: 4px 6px 0 rgba(indianred, 0.3); cursor: pointer; transition: all 0.2s; &:active { transform: translate(2px, 2px); } } @keyframes blink { 0%, 40%, 60%, 100% { transform: scaleY(1); } 50% { transform: scaleY(0.1); } } @keyframes fadeIn { from { opacity: 0; transform: translateY(-50%); } }
console.log("Event Fired") const { useState, useEffect } = React; // helpers const fileToImageSrc = async (file) => { const img = new Image(); const url = URL.createObjectURL(file); img.src = url; return new Promise((resolve, reject) => { img.onload = () => resolve(url); img.onerror = () => reject("image loaded error"); }); }; const randomRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; const getRandomColorSet = () => { const h = randomRange(0, 360); const s = randomRange(30, 60); const l = randomRange(80, 95); const darkL = l - 50; return { dark: `hsl(${h}, ${s}%, ${darkL}%)`, light: `hsl(${h}, ${s}%, ${l}%)` }; }; const App = () => { const [isDragging, setIsDragging] = useState(false); const [eyesMove, setEyesMove] = useState({ x: 0, y: 0 }); const [uploadedImage, setUploadedImage] = useState(""); const [message, setMessage] = useState(""); const handleMouseMove = (e) => { const ratio = 0.3; const centerX = window.innerWidth / 2; const centerY = window.innerHeight / 2; const x = ((e.clientX - centerX) / centerX) * ratio; const y = ((e.clientY - centerY) / centerY) * ratio; setEyesMove({ x, y }); }; const onDragOver = (e) => { e.preventDefault(); setIsDragging(true); handleMouseMove(e); }; const onDragLeave = () => { setIsDragging(false); setEyesMove({ x: 0, y: 0 }); }; const onDrop = async (e) => { e.preventDefault(); setIsDragging(false); setEyesMove({ x: 0, y: 0 }); const file = e.dataTransfer.files[0]; onUpload(file); }; const onInputChange = (e) => { const file = e.target.files[0]; onUpload(file); }; const onUpload = async (file) => { const acceptTypes = /image\/(jpg|jpeg|png)$/i; if (acceptTypes.exec(file.type) === null) { showMessage("Not a valid image"); return; } const imageSrc = await fileToImageSrc(file); if (imageSrc) { setUploadedImage(imageSrc); } }; const showMessage = async (msg, duration = 3000) => { if (!msg) return; setMessage(msg); await new Promise((r) => setTimeout(r, duration)); setMessage(""); }; const onReset = () => { setUploadedImage(""); }; useEffect(() => { // initialize color set const { dark, light } = getRandomColorSet(); document.body.style.setProperty("--dark-color", dark); document.body.style.setProperty("--light-color", light); }, []); return (
{uploadedImage ? (
) : ( <>
Drop your image here
> )} {uploadedImage && (
Reset
)} {message &&
{message}
}
); }; ReactDOM.render(
, document.getElementById("root"));